//-----------------------------------------------------
// Design Name : 
// File Name : 
// Function : 
//-----------------------------------------------------
module VGAController (
	input clock,
	input reset,
	input [15:0] memory,
	output reg read,
	output reg [2:0] VGAout,
	output reg vSyncOut,
	output reg hSyncOut,
	output reg startToRead,
	output reg resetCounter,
	output reg [7:0] hPixelCount
	); 
reg clk;
reg count;
always@(posedge clock)
begin
	if(reset)
	begin
	clk <= 0;
	count <= 0;
	end
	else if(count == 1)
	clk <= ~clk;
	else
	count <= count +1;
end

// Internal Registers
reg [18:0] vCount;
reg [9:0] hCount;
reg vDrawing;
reg hDrawing;

// Parameters

// Timings for 480x480 at 25 MHz from the
// Spartan 3E User's Guide
parameter VSYNC_PULSE_WIDTH = 19'd1600;
parameter VBACK_PORCH_WIDTH = 19'd23200;
parameter VACTIVE_WIDTH = 19'd384000;
parameter VFRONT_PORCH_WIDTH = 19'd8000;
parameter HSYNC_PULSE_WIDTH = 10'd96;
parameter HBACK_PORCH_WIDTH = 10'd48;
parameter HACTIVE_WIDTH = 10'd640;
parameter HFRONT_PORCH_WIDTH = 10'd16;
	
parameter VSYNC_PULSE_START = 19'd0;
parameter VBACK_PORCH_START = VSYNC_PULSE_WIDTH;
parameter VACTIVE_START = VSYNC_PULSE_WIDTH + VBACK_PORCH_WIDTH;
parameter VFRONT_PORCH_START = VSYNC_PULSE_WIDTH + VBACK_PORCH_WIDTH + VACTIVE_WIDTH;
parameter VCYCLE_END = VSYNC_PULSE_WIDTH + VBACK_PORCH_WIDTH + VACTIVE_WIDTH + VFRONT_PORCH_WIDTH - 1;
	
parameter HSYNC_PULSE_START = 10'd0;
parameter HBACK_PORCH_START = HSYNC_PULSE_WIDTH;
parameter HACTIVE_START = HSYNC_PULSE_WIDTH + HBACK_PORCH_WIDTH;
parameter HFRONT_PORCH_START = HSYNC_PULSE_WIDTH + HBACK_PORCH_WIDTH + HACTIVE_WIDTH;
parameter HCYCLE_END = HSYNC_PULSE_WIDTH + HBACK_PORCH_WIDTH + HACTIVE_WIDTH + HFRONT_PORCH_WIDTH - 1;
parameter HSTART_WRITE = HACTIVE_START+80;
parameter HSTOP_WRITE = HFRONT_PORCH_START - 80;

// Implementation
always @ (posedge clk)
begin
	startToRead <= 0;
	resetCounter <= 0;
	if (reset == 1'b1 || vCount == VCYCLE_END)	
	begin
		// Reset everything
		vCount <= 19'b0;
		hCount <= 10'b0;
		hPixelCount <= 9'b0;
		vDrawing <= 1'b0;
		hDrawing <= 1'b0;
		read <= 1'b0;
		VGAout <= 6'b0;
		vSyncOut <= 1'b1;
		hSyncOut <= 1'b1;
		resetCounter <= 1;
	end
	else begin
		//Always increment counts
		vCount <= vCount + 1;
		hCount <= hCount + 1;
		
		//V-Count State Machine
		if (vCount == VSYNC_PULSE_START) 
		begin
			vSyncOut <= 1'b0;
		end
		else if (vCount == VBACK_PORCH_START) 
		begin
			vSyncOut <= 1'b1;
		end
		else if (vCount == VACTIVE_START) 
		begin
			vDrawing <= 1'b1;
		end
		else if (vCount == VFRONT_PORCH_START) 
		begin
			vDrawing <= 1'b0;
		end
		
		//H-Count State Machine
		if (hCount == HSYNC_PULSE_START) 
		begin
			hSyncOut <= 1'b0;
		end
		else if (hCount == HBACK_PORCH_START) 
		begin
			hSyncOut <= 1'b1;
		end
		else if (hCount == HSTART_WRITE) 
		begin
			hDrawing <= 1'b1;
		end
		else if (hCount == HSTOP_WRITE) 
		begin
			startToRead <= 1'b1;
			hDrawing <= 1'b0;
			if (vDrawing == 1'b1) 
			begin
				// Update Pixel Count and Current Vertical Block Position
				hPixelCount <= 9'b0;
			end
		end
		else if (hCount == HCYCLE_END) 
		begin
			hCount <= 10'b0;
		end
		
		//Output selector
		if (vDrawing == 1'b1 && hDrawing == 1'b1)	
		begin
			
			//Even pixel - Read 16-bit word from block ram and output lower byte of read data
			if (hCount[0] == 1'b0) 
			begin
				read <= 1;
				//VGAout <= 3'b101;
				VGAout[2] <= memory[6];
				VGAout[1] <= memory[4];
				VGAout[0] <= memory[2];
				hPixelCount <= hPixelCount + 1;
			end
			//Odd pixel - Deassert read signal and output upper byte of read data
			else 
			begin
				read <= 1'b1;
//				VGAout <= 3'b101;
				VGAout[2] <= memory[14];
				VGAout[1] <= memory[12];
				VGAout[0] <= memory[10];
			end
		end
		else 
		begin
			read <= 1'b0;
			//address <= 14'b0;
			VGAout <= 6'b0;
		end
		
	end
end

endmodule 